package com.google.code.coma.space;

import com.google.code.coma.domain.Order;
import com.google.code.coma.domain.Part;
import com.google.code.coma.domain.Type;
import org.mozartspaces.capi3.Capi3Exception;
import org.mozartspaces.capi3.CountNotMetException;
import org.mozartspaces.capi3.javanative.operation.NativeEntry;

import java.util.*;

/**
 * Callback which selects all parts which are neccessary to assemble a computer
 *
 * @author Bernhard Nickel, e0925384@student.tuwien.ac.at
 * @author Dominik Strasser, dominikstr@gmail.com
 */
public class ComputerPartSelectorCallback implements SelectorCallback {
	private Order order;

	public ComputerPartSelectorCallback() {
	}

	public ComputerPartSelectorCallback(Order order) {
		this.order = order;
	}

	@Override
	public List<NativeEntry> doInTransaction(Collection<NativeEntry> coordinatorCollection, CallContext callContext) throws Capi3Exception {
		if (order == null) {
			NativeEntry cpu = null;
			NativeEntry mainboard = null;
			NativeEntry graphicsCard = null;

			List<NativeEntry> computerParts = new ArrayList<NativeEntry>();

			if (coordinatorCollection.size() > 2) {

				for (NativeEntry entry : coordinatorCollection) {
					if ((entry.getData() instanceof Part)) {
						Part part = (Part) entry.getData();

						if (part.getType().equals(Type.CPU)) {
							if (cpu == null) {
								cpu = entry;
							}
						} else if (part.getType().equals(Type.Mainboard)) {
							if (mainboard == null) {
								mainboard = entry;
							}
						} else if (part.getType().equals(Type.RAM)) {
							if (computerParts.size() < 4) {
								computerParts.add(entry);
							}
						} else if (part.getType().equals(Type.GraphicsCard)) {
							if (graphicsCard == null) {
								graphicsCard = entry;
							}
						}
					}

					//Ready, no need for further possible parts
					if (cpu != null && mainboard != null && graphicsCard != null && computerParts.size() == 4) {
						computerParts.add(cpu);
						computerParts.add(mainboard);
						computerParts.add(graphicsCard);
						return computerParts;
					}
				}

				//check found parts
				if (cpu != null && mainboard != null & computerParts.size() > 0) {
					if (computerParts.size() == 3) {
						computerParts.remove(2);
					}

					computerParts.add(cpu);
					computerParts.add(mainboard);

					if (graphicsCard != null) {
						computerParts.add(graphicsCard);
					}

					return computerParts;
				}
			}
			return Collections.emptyList();
		} else {
			if (order.isFinished()) return Collections.emptyList();
			NativeEntry cpu = null;
			NativeEntry mainboard = null;
			NativeEntry graphics = null;
			List<NativeEntry> rams = new ArrayList<NativeEntry>();
			for (NativeEntry e : coordinatorCollection) {
				if (e.getData() instanceof Part) {
					Part p = (Part) e.getData();
					if (cpu == null && p.getType() == Type.CPU && p.getAppellation().equals(order.getCpuType())) {
						cpu = e;
					} else if (rams.size() < order.getNumberOfRAMModules() && p.getType() == Type.RAM) {
						rams.add(e);
					} else if (order.isGraphicsCard() && graphics == null) {
						graphics = e;
					} else if (mainboard == null && p.getType() == Type.Mainboard) {
						mainboard = e;
					}
				}
			}
			if (cpu == null || mainboard == null || rams.size() != order.getNumberOfRAMModules() || (order.isGraphicsCard() && graphics == null))
				return Collections.emptyList();
			List<NativeEntry> resultList = new ArrayList<NativeEntry>();
			resultList.add(cpu);
			resultList.add(mainboard);
			resultList.addAll(rams);
			if (order.isGraphicsCard())
				resultList.add(graphics);
			return resultList;
		}
	}
}
